﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using MvcContrib.ObjectBuilder;
using System.IO;
using System.Web.Mvc;
using MvcServiceLibrary;
using MvcContrib.ControllerFactories;
using System.Reflection;

namespace JqueryMvc
{
    abstract public class JqueryMvcApplication : HttpApplication, IDependencyContainerAccessor
    {

        public override void Init()
        {
            base.Init();
            InitializeContainer();
        }

        #region IoC
        virtual public void InitializeContainer()
        {
            lock (containerLock)
            {
                string configFile = Path.Combine(HttpRuntime.AppDomainAppPath, "DependencyContainer.config");
                if (File.Exists(configFile))
                    container = new DependencyContainer(File.ReadAllText(configFile));
                else
                    container = new DependencyContainer();

            }
            container.RegisterInstance<DependencyContainer>(container);
            container.RegisterTypeMapping<IDependencyContainer, DependencyContainer>();
            container.RegisterTypeMapping<IViewFactory, ServiceViewFactory>();

            foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
            {
                Type[] assemblyTypes = a.GetTypes();
                foreach (Type type in assemblyTypes)
                {
                    if (typeof(IController).IsAssignableFrom(type))
                    {
                        AddController(type);
                    }
                }
            }

            ControllerBuilder.Current.SetDefaultControllerFactory(typeof(ObjectBuilderControllerFactory));

        }

        virtual protected void AddController(Type controller)
        {
            container.RegisterTypeMapping(controller, controller);
            if (typeof(Controller).IsAssignableFrom(controller))
                container.RegisterPropertySetter(controller, "ViewFactory", typeof(IViewFactory));
        }

        static object containerLock = new object();
        static DependencyContainer container;
        public DependencyContainer Container
        {
            get
            {
                if (container == null)
                    InitializeContainer();
                return container;
            }
        }
        #endregion


        #region IoC Helper Methods
        virtual protected void InstantiateFromNamespace(Type typeInNs, bool recursive)
        {
            Type[] types = typeInNs.Assembly.GetTypes();
            foreach (Type type in types)
            {
                if ((recursive && type.Namespace != null && type.Namespace.StartsWith(typeInNs.Namespace))
                    ||
                    (type.Namespace == typeInNs.Namespace))
                {
                    if (!type.IsInterface)
                        container.Get(type);
                }
            }
        }


        virtual protected void AddFromNamespace(Type typeInNs, bool useInterfaces, bool recursive, bool asSingleton)
        {
            Type[] types = typeInNs.Assembly.GetTypes();
            foreach (Type type in types)
            {
                if ((recursive && type.Namespace != null && type.Namespace.StartsWith(typeInNs.Namespace))
                    ||
                    (type.Namespace == typeInNs.Namespace))
                {
                    if (asSingleton)
                    {
                        container.RegisterSingleton(type);
                    }
                    AddType(type, useInterfaces);
                }
            }
        }

        virtual protected void AddType(Type type, bool useInterfaces)
        {
            if (type.IsAbstract || !type.IsClass)
                return;
            if (useInterfaces)
            {
                Type serviceType = GetServiceType(type);
                if (serviceType == null)
                    return;
                AddService(serviceType, type);
            }
            else
                AddService(type);
        }

        virtual protected string GetTypeKey(Type type)
        {
            return type.FullName;
        }

        virtual protected Type GetServiceType(Type type)
        {
            Type[] interfaces = type.FindInterfaces(new TypeFilter(delegate(Type t, object o) { return true; }), null);
            foreach (Type iface in interfaces)
            {
                return iface;
            }
            return null;
        }

        virtual protected void AddService(Type serviceType, Type type)
        {
            Container.RegisterTypeMapping(serviceType, type);
        }

        virtual protected void AddService(Type type)
        {
            Container.RegisterTypeMapping(type, type);
        }
        #endregion

        #region IContainerAccessor Members

        IDependencyContainer IDependencyContainerAccessor.Container
        {
            get { return Container; }
        }

        #endregion
    }
}
